package frame.laxcen;

import frame.laxcen.exception.IllegalFrameFormatException;
import frame.laxcen.response.IResponse;
import frame.laxcen.util.Algorithm;
import frame.laxcen.util.FrameReader;
import util.ByteUtil;
import java.util.Arrays;

public class BaseFrame {

    public byte[] FrameBytes;

    public byte FrameHead;

    public ControlWord CW;

    public int FrameDataLength;

    public byte[] FrameData;

    public byte[] CRC;

    public byte[] CRCData;

    protected  BaseFrame() { }

    public BaseFrame(byte[] bytes) throws IllegalFrameFormatException  {

        initialize(bytes);
    }

    protected BaseFrame initialize(byte[] bytes) throws IllegalFrameFormatException {

        FrameReader reader = new FrameReader(bytes);

        try {

            this.FrameBytes = bytes;

            this.FrameHead = reader.readU8();

            this.CW = new ControlWord(ByteUtil.shortToBytes(reader.readU16()));

            this.FrameDataLength = Short.toUnsignedInt(reader.readU16());

            this.FrameData = reader.readU8n(this.FrameDataLength);

            this.CRC = ByteUtil.shortToBytes(reader.readU16());

            this.CRCData = Arrays.copyOfRange(bytes, 1, bytes.length - 2);

        } catch (Exception e) {

            e.printStackTrace();

            throw new IllegalFrameFormatException(e.toString());
        }

        if(Byte.compare(this.FrameHead, (byte) 0xaa) != 0) {

            throw new IllegalFrameFormatException("FrameHead was expected to 0XAA.");
        }

        if(!Algorithm.checkCRC(this.CRCData, this.CRC)) {

            throw new IllegalFrameFormatException("CRC check failed.");
        }

        return this;
    }

    public boolean isResponse(Class<? extends IResponse> responseType) {

        String[] part = responseType.getName().split("_");

        if(part.length != 3) return false;

        boolean isMessageTypeEqual = Byte.compare(CW.MessageType, Integer.valueOf(part[1], 16).byteValue()) == 0;

        boolean isMIDEqual = Byte.compare(CW.MID, Integer.valueOf(part[2], 16).byteValue()) == 0;

        return isMessageTypeEqual && isMIDEqual;
    }

    public static class ControlWord {

        public final byte MID;

        public final byte MessageType;

        public final boolean IsUpload;

        private ControlWord(byte[] data) {

            this.MID = data[1];

            this.MessageType = data[0];

            this.IsUpload = ByteUtil.isNotZeroBit(data[0], 4);
        }
    }
}
